package pATT.profilingAlgorithm.PersonalSearcher;



import java.io.Serializable;
import java.util.StringTokenizer;
import java.util.TreeMap;



/**
 * A document which can identify HTML Tags and pull out HTML info.  In addition
 * to the SimpleDocument methods, this class can find specific HTML elements,
 * if they exist.  This document does not assume that the HTML document is
 * properly written, so it won't choke on poorly formed HTML.  
 * 
 * @since September 2000
 * @author <a href="mailto:trbauer@indiana.edu>Travis Bauer</a>
 * @version 0.1
 */
public class HTMLDocument extends AbstractDocument implements Serializable {

  /**
	 * 
	 */
	private static final long serialVersionUID = 1L;
public static final int STYLE_H1=100;
  public static final int STYLE_H2=101;
  public static final int STYLE_H3=102;
  public static final int STYLE_H4=103;
  public static final int STYLE_ANCHOR=104;  

  private static String url;  

  /**
   * Creates new HTMLDocument
   * 
   * @param contents The HTML document
   */
  public HTMLDocument(String contents, String u) {
    setFullContent(contents);
    url =u;
  }

  public String getURL() {
  	return url;
  }

  public String getIndexibleContent() {
    String s = super.getIndexibleContent();
    if (s==null) {
      setIndexibleContent(calculateIndexibleContent());
      return super.getIndexibleContent();
    } else {
      return s;
    }
  }

  /**
   * Returns title, if present.  Otherwise returns null.  If you have
   * badly formed HTML and there are multiple title tags, only the first
   * is returned
   */
  public String getTitle() {
    String titleTags[] = StringTools.taggedStrings
      (getFullContent(), "<title>", "</title>", false);
    if (titleTags.length==0) return null;
    return titleTags[0];
  }

  /**
   * Returns all of the text in body tags.  If there are no <body> tags,
   * null is returns.  If there is more than one, all are returned
   * concatenated onto one another.  Other embedded HTML tags are not removed.
   */
  public String getBodyText() {
    String bodyTags[] =
      StringTools.taggedStrings(getFullContent(), "<body>", "</body>", false);
    if (bodyTags.length==0) return null;
    StringBuffer sb = new StringBuffer();
    for (int i= 0; i<bodyTags.length; i++) {
      sb.append(bodyTags[i]+" ");
    }
    return sb.toString();
  }

  /**
   * Returns the information stored in the meta tags of an HTML document.
   * assumes that the name and content are surrounded by double quotes.
   *
   * @return a <code>TreeMap</code> value
   */
  @SuppressWarnings("unchecked")
public TreeMap metaTagInfo() {
    String contents = getFullContent().toLowerCase();
    TreeMap metaTags = new TreeMap();
    int currPos=contents.indexOf("meta");
    while(currPos!=-1) {
      currPos=contents.indexOf("name", currPos);
      currPos=contents.indexOf("\"", currPos);
      currPos++;
      int endPos = contents.indexOf("\"", currPos);
      String key=contents.substring(currPos, endPos);

      currPos=contents.indexOf("content", endPos);
      currPos=contents.indexOf("\"", currPos);
      currPos++;
      endPos=contents.indexOf("\"", currPos);
      String value = contents.substring(currPos, endPos);
      value = StringTools.replaceAll(value, "\n", " ");

      metaTags.put(key, value);

      currPos=contents.indexOf("meta", currPos);
    }
    return metaTags;
  }

  /**
   * Returns the text of various styles.  In the current implementation,
   * if the STYLE_EMPHASIZED and STYLE_DEEMPHSIZED do not necessarily
   * return the text in the order in which is appears in the document.
   * STYLE_EMPHASIZED returns H1-4, bold, and italic text.
   *
   * @param style an <code>int</code> value
   * @return a <code>String</code> value
   */
  public String getStylizedText(int style) {
    String emphTags[][] = {
      {"<b>", "</b>"},
      {"<i>", "</i>"},
      {"<h1>", "</h1>"},
      {"<h2>", "</h2>"},
      {"<h3>", "</h3>"},
      {"<h4>", "</h4>"}
    };
      
    String output[] =null;
    switch (style) {
      
      // bold text
    case STYLE_BOLD:
      output = StringTools.taggedStrings
	(getFullContent(), "<b>", "</b>", false);
      break;
      
      //italic text
    case STYLE_ITALIC:
      output = StringTools.taggedStrings
	(getFullContent(), "<i>", "</i>", false);
      break;

      //emphasized text
    case STYLE_EMPHSIZED:
      String outputs[][] = new String[emphTags.length][];
      //get the strings
      for (int i=0; i<emphTags.length; i++) {
	outputs[i]=StringTools.taggedStrings
	  (getFullContent(), emphTags[i][0], emphTags[i][1], false);
      }
      
      //put them together
      StringBuffer sb = new StringBuffer();
      for (int i=0; i<outputs.length; i++) {
	for (int j=0; j<outputs[i].length; i++) {
	  sb.append(outputs[i][j]);
	  if ((j<outputs[i].length-1)||(i<outputs.length-1))
	    sb.append(" ");
	}
      }
      return sb.toString();
      
    }
    if (output!=null) {
      return StringTools.concat(output, ' ');
    } else {
      return null;
    }
  }

  /** Calculates what the content Text is
   */
  private String calculateIndexibleContent() {
   
    String indexibleContent = StringTools.removeTaggedStrings
      (getFullContent(), "<style", "</style>", false);
    indexibleContent = StringTools.removeTaggedStrings
      (indexibleContent, "<script", "</script>", false);
    indexibleContent = StringTools.removeHtmlTags(indexibleContent);
    //don't drop &nbsp; because the ; may still be word delimiter
    indexibleContent = StringTools.replaceAll(indexibleContent, "&nbsp;", " ");
    indexibleContent = StringTools.replaceAll(indexibleContent, "&#149;", " ");
    indexibleContent = StringTools.replaceAll(indexibleContent, "&quot;", " ");
    indexibleContent = StringTools.replaceAll(indexibleContent, "&deg;", " ");
    //the following space gets rid of punctuations/white space
    StringBuffer sb = new StringBuffer();
    StringTokenizer st = new StringTokenizer(indexibleContent,
					     IOTools.GENERIC_WORD_DELIMITERS);
    while(st.hasMoreTokens()) {
      String candidate = st.nextToken();
      if (candidate.length()>1)
	sb.append(candidate.toLowerCase()+" ");
    }
    indexibleContent = sb.toString();
    return indexibleContent;
  }        
}